Objective: Learn the basics of `ggplot2()’ by visualizing a sample
data set
Learning Outcomes: Understand the purpose and effective use of the
following tools –line chart, histogram, box plot, scatter plot, bubble
chart, and bullet graph.
Clear the workspace
Let’s start with cleaning the workspace and loading the required
packages. Today, we will use a new package, ggplot2(),
which is a powerful R graphic package. I highly recommend this site (and
book) for more examples: http://www.cookbook-r.com/Graphs/
rm(list = ls())
library(readxl)
library(tidyverse)
library(ggplot2)
Understanding the dataset
In this exercise, we will use the crime statistics in large U.S.
cities for 2009-2014. This dataset is obtained from the Uniform Crime
Reports (UCR) published by the FBI (https://ucr.fbi.gov/crime-in-the-u.s/2014/crime-in-the-u.s.-2014).
This file includes the number of crime occurrences per population (crime
rates) and the number of police officers killed or assaulted in the line
of duty.
- Download Crimes 2009-2014.xlsx from Canvas Modules >
Week 2.
- Open the file in Excel, and browse the data.
- Take a look at Data Dictionary tab, and understand what each crime
data attribute is for.
crimes <- read_excel("Crimes 2009-2014.xlsx")
crimes
glimpse(crimes)
Rows: 1,546
Columns: 10
$ City <chr> "Anchorage", "Anchorage", "Anchorage", "Anchorage", "Anchorage", "Anchorage", "Anchorage", "Anchorage", "Ancho…
$ State <chr> "AK", "AK", "AK", "AK", "AK", "AK", "AK", "AK", "AK", "AK", "AK", "AK", "AK", "AK", "AK", "AK", "AL", "AL", "A…
$ Region <chr> "Pacific", "Pacific", "Pacific", "Pacific", "Pacific", "Pacific", "Pacific", "Pacific", "Pacific", "Pacific", …
$ Year <chr> "12-31-1999", "12-31-2000", "12-31-2001", "12-31-2002", "12-31-2003", "12-31-2004", "12-31-2005", "12-31-2006"…
$ Population <dbl> 257762, 260283, 263588, 267280, 271085, 273714, 276109, 277692, 284142, 280068, 283300, 291826, 296955, 299143…
$ `Murder Rate` <dbl> 8.147050, 5.378761, 4.173179, 7.108650, 7.008872, 5.845518, 6.519165, 7.202224, 7.742608, 4.284674, 5.294741, …
$ `Violent Crime Rate` <dbl> 1829.2068, 1714.2879, 1863.5143, 1807.4678, 1687.6625, 1593.6342, 1653.6947, 1912.9107, 1960.9913, 2268.3777, …
$ `Violent Crime Rate in Prior Year` <dbl> NA, 1829.2068, 1714.2879, 1863.5143, 1807.4678, 1687.6625, 1593.6342, 1653.6947, 1912.9107, 1960.9913, 2268.37…
$ `Property Crime Rate` <dbl> 4370.311, 4357.565, 4349.970, 4470.593, 4318.203, 3617.279, 4116.128, 4220.863, 3908.961, 3288.844, 3641.370, …
$ `Officer Assault Rate` <dbl> 30.648428, 24.588621, 32.626675, 31.801856, 30.986591, 39.457244, 41.650218, 39.972343, 58.773430, 61.056601, …
Data Preparation
The names of variables contain spaces, which make it difficult to
manage in R. Let’s rename variables.
# Change the variable names
colnames(crimes)<-c("city","state","region","date","population","murder_rate","violent_crime_rate","violent_crime_rate_pr","property_crime_rate","officer_assault_rate")
glimpse(crimes)
Rows: 1,546
Columns: 10
$ city <chr> "Anchorage", "Anchorage", "Anchorage", "Anchorage", "Anchorage", "Anchorage", "Anchorage", "Anchorage", "Anchorage", "Ancho…
$ state <chr> "AK", "AK", "AK", "AK", "AK", "AK", "AK", "AK", "AK", "AK", "AK", "AK", "AK", "AK", "AK", "AK", "AL", "AL", "AL", "AL", "AL…
$ region <chr> "Pacific", "Pacific", "Pacific", "Pacific", "Pacific", "Pacific", "Pacific", "Pacific", "Pacific", "Pacific", "Pacific", "P…
$ date <chr> "12-31-1999", "12-31-2000", "12-31-2001", "12-31-2002", "12-31-2003", "12-31-2004", "12-31-2005", "12-31-2006", "12-31-2007…
$ population <dbl> 257762, 260283, 263588, 267280, 271085, 273714, 276109, 277692, 284142, 280068, 283300, 291826, 296955, 299143, 299455, 301…
$ murder_rate <dbl> 8.147050, 5.378761, 4.173179, 7.108650, 7.008872, 5.845518, 6.519165, 7.202224, 7.742608, 4.284674, 5.294741, 4.797379, 4.3…
$ violent_crime_rate <dbl> 1829.2068, 1714.2879, 1863.5143, 1807.4678, 1687.6625, 1593.6342, 1653.6947, 1912.9107, 1960.9913, 2268.3777, 2433.1098, 22…
$ violent_crime_rate_pr <dbl> NA, 1829.2068, 1714.2879, 1863.5143, 1807.4678, 1687.6625, 1593.6342, 1653.6947, 1912.9107, 1960.9913, 2268.3777, 2433.1098…
$ property_crime_rate <dbl> 4370.311, 4357.565, 4349.970, 4470.593, 4318.203, 3617.279, 4116.128, 4220.863, 3908.961, 3288.844, 3641.370, 3500.031, 318…
$ officer_assault_rate <dbl> 30.648428, 24.588621, 32.626675, 31.801856, 30.986591, 39.457244, 41.650218, 39.972343, 58.773430, 61.056601, 61.418990, 76…
Also, change the variable type of date as a date
variable and create year for further analysis.
# create year variable
crimes$date<-as.Date(crimes$date,"%m-%d-%Y")
crimes
crimes$year<-format(crimes$date,"%Y")
glimpse(crimes)
Rows: 1,546
Columns: 11
$ city <chr> "Anchorage", "Anchorage", "Anchorage", "Anchorage", "Anchorage", "Anchorage", "Anchorage", "Anchorage", "Anchorage", "Ancho…
$ state <chr> "AK", "AK", "AK", "AK", "AK", "AK", "AK", "AK", "AK", "AK", "AK", "AK", "AK", "AK", "AK", "AK", "AL", "AL", "AL", "AL", "AL…
$ region <chr> "Pacific", "Pacific", "Pacific", "Pacific", "Pacific", "Pacific", "Pacific", "Pacific", "Pacific", "Pacific", "Pacific", "P…
$ date <date> 1999-12-31, 2000-12-31, 2001-12-31, 2002-12-31, 2003-12-31, 2004-12-31, 2005-12-31, 2006-12-31, 2007-12-31, 2008-12-31, 20…
$ population <dbl> 257762, 260283, 263588, 267280, 271085, 273714, 276109, 277692, 284142, 280068, 283300, 291826, 296955, 299143, 299455, 301…
$ murder_rate <dbl> 8.147050, 5.378761, 4.173179, 7.108650, 7.008872, 5.845518, 6.519165, 7.202224, 7.742608, 4.284674, 5.294741, 4.797379, 4.3…
$ violent_crime_rate <dbl> 1829.2068, 1714.2879, 1863.5143, 1807.4678, 1687.6625, 1593.6342, 1653.6947, 1912.9107, 1960.9913, 2268.3777, 2433.1098, 22…
$ violent_crime_rate_pr <dbl> NA, 1829.2068, 1714.2879, 1863.5143, 1807.4678, 1687.6625, 1593.6342, 1653.6947, 1912.9107, 1960.9913, 2268.3777, 2433.1098…
$ property_crime_rate <dbl> 4370.311, 4357.565, 4349.970, 4470.593, 4318.203, 3617.279, 4116.128, 4220.863, 3908.961, 3288.844, 3641.370, 3500.031, 318…
$ officer_assault_rate <dbl> 30.648428, 24.588621, 32.626675, 31.801856, 30.986591, 39.457244, 41.650218, 39.972343, 58.773430, 61.056601, 61.418990, 76…
$ year <chr> "1999", "2000", "2001", "2002", "2003", "2004", "2005", "2006", "2007", "2008", "2009", "2010", "2011", "2012", "2013", "20…
Scatter plot
Let’s start by examining the relationship between the violent crime
rate and the property crime rate in the major cities. You can visualize
the relationship of two numeric variables by plotting a scatter plot
where x- and y-axis represents each numeric variable.
Base R plot function
Using base R plot function:
plot(crimes$violent_crime_rate, crimes$property_crime_rate)

However, the combination of tidyverse and
ggplot2 can help you create a nicer-looking chart in a more
intrinsic way with more flexibility.
ggplot: Intro
ggplot() takes a dataset as the first argument, and you
specify aesthetics (e.g. axes, color, type, etc) with the parameters in
aes().
In ggplot(), you specify the dataset and aesthetics, and
`geom_point() indicates you’d like to create a scatter plot.
ggplot(crimes, aes(x=violent_crime_rate,y=property_crime_rate))+
geom_point()

We can create the same plot with a pipe operator:
crimes%>%
ggplot(aes(x=violent_crime_rate,y=property_crime_rate))+
geom_point()

Change colors, data point sizes, etc
If you want to apply the different color, shape, etc, for
all points, you can do it by changing the parameter in
`geom_point()’.
crimes%>%
ggplot(aes(x=violent_crime_rate,y=property_crime_rate))+geom_point(size=5)

crimes%>%
ggplot(aes(x=violent_crime_rate,y=property_crime_rate))+geom_point(size=5, alpha=0.2) #alpha for transparency: for densely populated data points

crimes%>%
ggplot(aes(x=violent_crime_rate,y=property_crime_rate))+geom_point(col="blue")

crimes%>%
ggplot(aes(x=violent_crime_rate,y=property_crime_rate))+geom_point(shape=4)

crimes%>%
ggplot(aes(x=violent_crime_rate,y=property_crime_rate))+geom_point(col=2,shape=2,size =3)

crimes%>%
ggplot(aes(x=violent_crime_rate,y=property_crime_rate))+
geom_point(col="#86229A",shape=2,size =3)+
labs(title="Violent vs. Property Crime Rate", x="Violent Crime Rate", y="Property Crime Rate")

Different colors, sizes, etc. by groups
If you want to use different colors by different groups, you can do
it easily by setting it in aes()! You can change the
aesthetics to deliver more information on a chart.
crimes%>%
ggplot(aes(x=violent_crime_rate,y=property_crime_rate, size=officer_assault_rate))+geom_point()

crimes%>%
ggplot(aes(x=violent_crime_rate,y=property_crime_rate, col=region))+geom_point()

You can do it in combination!
crimes%>%
ggplot(aes(x=violent_crime_rate,y=property_crime_rate,size=officer_assault_rate,col=region))+
geom_point(shape=1)

Note that Officer Assault Rate is the number of police officers
killed or assaulted in the line of duty. This bubble chart now shows
that police officers are in more danger (as shown in bigger circles) in
cities with higher crime rates.
Facet
You can also easily create separate charts by subgroups (i.e. regions
in this case) using facet_wrap(), which creates charts,
which share the same axes, and displays them in a panel.
crimes%>%
ggplot(aes(y=property_crime_rate,x=violent_crime_rate,size=officer_assault_rate,colour=region))+
geom_point(shape=1)+
facet_wrap(~region)

Add a statistics layer
We can also add some statistical analysis results to the charts.
LOESS, which is a default smoothing method of
geom_smooth(), is a non-parametric form of regression that
uses a weighted, sliding-window, average to calculate a line of best
fit.
crimes%>%
ggplot(aes(x=violent_crime_rate,y=property_crime_rate))+
geom_point(shape=1)+
geom_smooth(method=loess)

A linear regression model can be added into a scatter plot by adding
specifying the smoothing method as “lm”.
crimes%>%
ggplot(aes(x=violent_crime_rate,y=property_crime_rate))+
geom_point(shape=1)+
geom_smooth(method=lm)

Using facet_wrap(), you can compare the trend by
different regions in the United States.fullrange=TRUE
extends the span of the linear model to the full range.
crimes%>%
ggplot(aes(x=violent_crime_rate,y=property_crime_rate, col=region))+
geom_point(shape=1)+
geom_smooth(method=lm,fullrange=TRUE)+
facet_wrap(~region)

Bar charts
A bar chart is a simple way to depict the frequencies of the values
of a categorical attribute.
How many cities are contained in this dataset by region? In fact, the
dataset is a panel dataset (i.e. repeated observations over time for the
same entities) at a city-year level, where each city appears once per
year. So, we can count the number of cities, if we set year
to a specific year (e.g. year=2000), and count the number
of observations.
Let’s filter data with year==2000 and then call
ggplot() with geom_bar() to create a bar
chart.
crimes%>%
filter(year==2000)%>%
ggplot(aes(x=region))+
geom_bar()

Histogram
A histogram shows the frequency distribution for a numerical
attribute.
The range of a numerical attribute is discretized into a fixed number
of intervals (“bins”), usually of equal length. For each interval, the
(absolute) frequency of values falling into each interval is indicated
by the height of a bar.
Let’s examine the distribution of the property crime rate.
crimes%>%
ggplot(aes(x=property_crime_rate))+
geom_histogram()

Change bin width, fill, color..
Try changing the value of binwidth. You will see the
shape of the histogram changes. Also, as we did with a scatterplot, you
can change the color of the histogram.
crimes%>%
ggplot(aes(x=property_crime_rate))+
geom_histogram(binwidth=1000, col="black",fill="red")

Overlapping histograms
We can easily create histograms for different regions using
facet_wrap().
crimes%>%
ggplot(aes(x=property_crime_rate, fill=region))+
geom_histogram(binwidth=100)+
facet_wrap(~region)

But you can also display these histograms in one chart with various
options.
crimes%>%
ggplot(aes(x=property_crime_rate,fill=region))+
geom_histogram(binwidth=100)

crimes%>%
ggplot(aes(x=property_crime_rate,fill=region))+
geom_histogram(binwidth=100,alpha=0.3, position="identity")

crimes%>%
ggplot(aes(x=property_crime_rate,fill=region))+
geom_histogram(binwidth=100,position="stack")

crimes%>%
ggplot(aes(x=property_crime_rate,fill=region))+
geom_histogram(binwidth=1000,position="dodge")

Instead of a histogram, you can create a density function in a
similar manner.
crimes%>%
ggplot(aes(x=property_crime_rate, fill=region))+
geom_density(alpha=0.5)

Box plot
A boxplot is a very compact way to visualize and summarize the key
statistics of a numeric attribute.
Let’s examine the distribution of the property crime rate (which will
be displayed in y-axis) by cities (which will be x-axis). Because we
have too many cities in our datasets, let’s focus on the cities in
Florida.
crimes%>%
filter(state=="FL")%>%
ggplot(aes(x=city,y=property_crime_rate,fill=city))+
geom_boxplot()

The upper whisker extends from the hinge to the largest value no
further than 1.5 * IQR from the hinge (where IQR is the inter-quartile
range, or distance between the first and third quartiles). The lower
whisker extends from the hinge to the smallest value at most 1.5 * IQR
of the hinge. Data beyond the end of the whiskers are called “outlying”
points and are plotted individually.
Time Series with Line Graph
Let’s examine the trend of the violent crime rate of the cities in
New York state. Let’s first examine the data.
crimes%>%
filter(state=="NY")%>%
distinct(city)
crimes%>%
filter(state=="NY")
For line graphs, the data points must be grouped so that it knows
which points to connect. If you want to connect all points, set
group=1. Because we want to connect the points by cities,
we will set group=city.
crimes%>%
filter(state=="NY")%>%
ggplot(aes(x=year,y=violent_crime_rate,group=city))+geom_line()

But we lost the information about which line is for which city. Let’s
use different types or colors of lines, so that we can distinguish
them.
crimes%>%
filter(state=="NY")%>%
ggplot(aes(x=year,y=violent_crime_rate, group=city,col=city))+geom_line()

crimes%>%
filter(state=="NY")%>%
ggplot(aes(x=year,y=violent_crime_rate, group=city,linetype=city))+geom_line()

Assignment 2
By modifying the code below, create box plots that show the range of
the violent crime rate for each state in the South region, where each
box represents a state. FYI, six states are categorized as South in the
dataset. After creating the chart, answer the following questions.
crimes %>%
filter(region == "South") %>%
ggplot(aes(x = state, y = violent_crime_rate, fill=state)) +
geom_boxplot()

Q1. Which state has the city that has the lowest violent crime rate
in the South region?
KY: Kentucky
Q2. Which state has the highest median value of the violent crime
rate?
Tennessee (TN)
Q3. By modifying the code below, create scatterplots that show the
relationship between the officer assault rate (x-axis) and the murder
rate (y-axis) by the states in the Northeast region. It will produce
four scatter plots with regression lines, one for each state.
Which state shows the strongest negative correlation
(i.e. the steeper, downward slope of regression lines)?
NJ : New Jersey
crimes %>%
filter(region == "Northeast") %>%
ggplot(aes(x = officer_assault_rate, y = murder_rate)) +
geom_point(shape = 1) +
geom_smooth(method = lm, fullrange = TRUE) +
facet_wrap(~ state)

Q4.By modifying the code below, create a histogram that shows the
distribution of property crime rate in year 2002. Set the binwidth=2000.
Which of the bins contains the largest number of cities?
crimes %>%
filter(year == "2002") %>%
ggplot(aes(x = property_crime_rate)) +
geom_histogram(binwidth = 2000, colour = "black", fill = "white")

- The bin whose x-axis values go from 0 to 2500.
- The bin whose x-axis values go from 2500 to 5000.
- The bin whose x-axis values go from 5000 to 7500.
- The bin whose x-axis values go from 7500 to 10000.
- The bin whose x-axis values go from 10000. to 12500
Answer: The bin whose x-axis values go from 5000 to 7500. This bin
contains more than 40 cities, making it the one with the largest number
of cities in 2002.
Q5. Similar to Assignment 1, generate a report from
“Creating-Charts-Student.Rmd”. This time, please knit it in a Word
document. Change the author name on the top of this R markdown file to
your name. Compile this R markdown file into a Word document and submit
it through the course Canvas. Your report should contain all the codes
and the results of in-class exercises as well as the codes for the
assignment questions.
Q6. Create a dashboard with Tableau by following the instruction in
“Creating-Charts-Tableau.doc”. After creating a dashboard, export your
Tableau dashboard view as PowerPoint. Click “File>Export As
Powerpoint”, and include “This View”. It will create a PPT file that
includes a snapshot of the dashboard. Submit this ppt file through
Canvas as your answer for Question 6.
LS0tCnRpdGxlOiAiRXhwbG9yYXRvcnkgQW5hbHlzaXMgd2l0aCBWaXN1YWxpemF0aW9uIgphdXRob3I6ICJQaXl1c2ggQWdyYXdhbCIKb3V0cHV0OgogIHdvcmRfZG9jdW1lbnQ6IGRlZmF1bHQKICBodG1sX25vdGVib29rOiBkZWZhdWx0CiAgcGRmX2RvY3VtZW50OiBkZWZhdWx0CiAgaHRtbF9kb2N1bWVudDoKICAgIGRmX3ByaW50OiBwYWdlZAotLS0KCk9iamVjdGl2ZTogTGVhcm4gdGhlIGJhc2ljcyBvZiBcYGdncGxvdDIoKScgYnkgdmlzdWFsaXppbmcgYSBzYW1wbGUgZGF0YSBzZXQKCkxlYXJuaW5nIE91dGNvbWVzOiBVbmRlcnN0YW5kIHRoZSBwdXJwb3NlIGFuZCBlZmZlY3RpdmUgdXNlIG9mIHRoZSBmb2xsb3dpbmcgdG9vbHMg4oCTbGluZSBjaGFydCwgaGlzdG9ncmFtLCBib3ggcGxvdCwgc2NhdHRlciBwbG90LCBidWJibGUgY2hhcnQsIGFuZCBidWxsZXQgZ3JhcGguCgojIENsZWFyIHRoZSB3b3Jrc3BhY2UKCkxldCdzIHN0YXJ0IHdpdGggY2xlYW5pbmcgdGhlIHdvcmtzcGFjZSBhbmQgbG9hZGluZyB0aGUgcmVxdWlyZWQgcGFja2FnZXMuIFRvZGF5LCB3ZSB3aWxsIHVzZSBhIG5ldyBwYWNrYWdlLCBgZ2dwbG90MigpYCwgd2hpY2ggaXMgYSBwb3dlcmZ1bCBSIGdyYXBoaWMgcGFja2FnZS4gSSBoaWdobHkgcmVjb21tZW5kIHRoaXMgc2l0ZSAoYW5kIGJvb2spIGZvciBtb3JlIGV4YW1wbGVzOiA8aHR0cDovL3d3dy5jb29rYm9vay1yLmNvbS9HcmFwaHMvPgoKYGBge3J9CnJtKGxpc3QgPSBscygpKQpsaWJyYXJ5KHJlYWR4bCkKbGlicmFyeSh0aWR5dmVyc2UpCmxpYnJhcnkoZ2dwbG90MikKYGBgCgojIFVuZGVyc3RhbmRpbmcgdGhlIGRhdGFzZXQKCkluIHRoaXMgZXhlcmNpc2UsIHdlIHdpbGwgdXNlIHRoZSBjcmltZSBzdGF0aXN0aWNzIGluIGxhcmdlIFUuUy4gY2l0aWVzIGZvciAyMDA5LTIwMTQuIFRoaXMgZGF0YXNldCBpcyBvYnRhaW5lZCBmcm9tIHRoZSBVbmlmb3JtIENyaW1lIFJlcG9ydHMgKFVDUikgcHVibGlzaGVkIGJ5IHRoZSBGQkkgKDxodHRwczovL3Vjci5mYmkuZ292L2NyaW1lLWluLXRoZS11LnMvMjAxNC9jcmltZS1pbi10aGUtdS5zLi0yMDE0PikuIFRoaXMgZmlsZSBpbmNsdWRlcyB0aGUgbnVtYmVyIG9mIGNyaW1lIG9jY3VycmVuY2VzIHBlciBwb3B1bGF0aW9uIChjcmltZSByYXRlcykgYW5kIHRoZSBudW1iZXIgb2YgcG9saWNlIG9mZmljZXJzIGtpbGxlZCBvciBhc3NhdWx0ZWQgaW4gdGhlIGxpbmUgb2YgZHV0eS4KCjEpICBEb3dubG9hZCAqQ3JpbWVzIDIwMDktMjAxNC54bHN4KiBmcm9tIENhbnZhcyAqTW9kdWxlcyBcPiBXZWVrIDIqLgoyKSAgT3BlbiB0aGUgZmlsZSBpbiBFeGNlbCwgYW5kIGJyb3dzZSB0aGUgZGF0YS4KMykgIFRha2UgYSBsb29rIGF0IERhdGEgRGljdGlvbmFyeSB0YWIsIGFuZCB1bmRlcnN0YW5kIHdoYXQgZWFjaCBjcmltZSBkYXRhIGF0dHJpYnV0ZSBpcyBmb3IuCgpgYGB7cn0KY3JpbWVzIDwtIHJlYWRfZXhjZWwoIkNyaW1lcyAyMDA5LTIwMTQueGxzeCIpCgpjcmltZXMKYGBgCgpgYGB7cn0KZ2xpbXBzZShjcmltZXMpCmBgYAoKIyBEYXRhIFByZXBhcmF0aW9uCgpUaGUgbmFtZXMgb2YgdmFyaWFibGVzIGNvbnRhaW4gc3BhY2VzLCB3aGljaCBtYWtlIGl0IGRpZmZpY3VsdCB0byBtYW5hZ2UgaW4gUi4gTGV0J3MgcmVuYW1lIHZhcmlhYmxlcy4KCmBgYHtyfQojIENoYW5nZSB0aGUgdmFyaWFibGUgbmFtZXMKY29sbmFtZXMoY3JpbWVzKTwtYygiY2l0eSIsInN0YXRlIiwicmVnaW9uIiwiZGF0ZSIsInBvcHVsYXRpb24iLCJtdXJkZXJfcmF0ZSIsInZpb2xlbnRfY3JpbWVfcmF0ZSIsInZpb2xlbnRfY3JpbWVfcmF0ZV9wciIsInByb3BlcnR5X2NyaW1lX3JhdGUiLCJvZmZpY2VyX2Fzc2F1bHRfcmF0ZSIpCmdsaW1wc2UoY3JpbWVzKQpgYGAKCkFsc28sIGNoYW5nZSB0aGUgdmFyaWFibGUgdHlwZSBvZiBgZGF0ZWAgYXMgYSBkYXRlIHZhcmlhYmxlIGFuZCBjcmVhdGUgYHllYXJgIGZvciBmdXJ0aGVyIGFuYWx5c2lzLgoKYGBge3J9CiMgY3JlYXRlIHllYXIgdmFyaWFibGUKY3JpbWVzJGRhdGU8LWFzLkRhdGUoY3JpbWVzJGRhdGUsIiVtLSVkLSVZIikKY3JpbWVzCmNyaW1lcyR5ZWFyPC1mb3JtYXQoY3JpbWVzJGRhdGUsIiVZIikKZ2xpbXBzZShjcmltZXMpCmBgYAoKIyBTY2F0dGVyIHBsb3QKCkxldCdzIHN0YXJ0IGJ5IGV4YW1pbmluZyB0aGUgcmVsYXRpb25zaGlwIGJldHdlZW4gdGhlIHZpb2xlbnQgY3JpbWUgcmF0ZSBhbmQgdGhlIHByb3BlcnR5IGNyaW1lIHJhdGUgaW4gdGhlIG1ham9yIGNpdGllcy4gWW91IGNhbiB2aXN1YWxpemUgdGhlIHJlbGF0aW9uc2hpcCBvZiB0d28gbnVtZXJpYyB2YXJpYWJsZXMgYnkgcGxvdHRpbmcgYSBzY2F0dGVyIHBsb3Qgd2hlcmUgeC0gYW5kIHktYXhpcyByZXByZXNlbnRzIGVhY2ggbnVtZXJpYyB2YXJpYWJsZS4KCiMjIEJhc2UgUiBwbG90IGZ1bmN0aW9uCgpVc2luZyBiYXNlIFIgcGxvdCBmdW5jdGlvbjoKCmBgYHtyfQpwbG90KGNyaW1lcyR2aW9sZW50X2NyaW1lX3JhdGUsIGNyaW1lcyRwcm9wZXJ0eV9jcmltZV9yYXRlKQpgYGAKCkhvd2V2ZXIsIHRoZSBjb21iaW5hdGlvbiBvZiBgdGlkeXZlcnNlYCBhbmQgYGdncGxvdDJgIGNhbiBoZWxwIHlvdSBjcmVhdGUgYSBuaWNlci1sb29raW5nIGNoYXJ0IGluIGEgbW9yZSBpbnRyaW5zaWMgd2F5IHdpdGggbW9yZSBmbGV4aWJpbGl0eS4KCiMjIGdncGxvdDogSW50cm8KCmBnZ3Bsb3QoKWAgdGFrZXMgYSBkYXRhc2V0IGFzIHRoZSBmaXJzdCBhcmd1bWVudCwgYW5kIHlvdSBzcGVjaWZ5IGFlc3RoZXRpY3MgKGUuZy4gYXhlcywgY29sb3IsIHR5cGUsIGV0Yykgd2l0aCB0aGUgcGFyYW1ldGVycyBpbiBgYWVzKClgLgoKSW4gYGdncGxvdCgpYCwgeW91IHNwZWNpZnkgdGhlIGRhdGFzZXQgYW5kIGFlc3RoZXRpY3MsIGFuZCBcYGdlb21fcG9pbnQoKSBpbmRpY2F0ZXMgeW91J2QgbGlrZSB0byBjcmVhdGUgYSBzY2F0dGVyIHBsb3QuCgpgYGB7cn0KZ2dwbG90KGNyaW1lcywgYWVzKHg9dmlvbGVudF9jcmltZV9yYXRlLHk9cHJvcGVydHlfY3JpbWVfcmF0ZSkpKwogIGdlb21fcG9pbnQoKQpgYGAKCldlIGNhbiBjcmVhdGUgdGhlIHNhbWUgcGxvdCB3aXRoIGEgcGlwZSBvcGVyYXRvcjoKCmBgYHtyfQpjcmltZXMlPiUKICBnZ3Bsb3QoYWVzKHg9dmlvbGVudF9jcmltZV9yYXRlLHk9cHJvcGVydHlfY3JpbWVfcmF0ZSkpKwogIGdlb21fcG9pbnQoKQpgYGAKCiMjIENoYW5nZSBjb2xvcnMsIGRhdGEgcG9pbnQgc2l6ZXMsIGV0YwoKSWYgeW91IHdhbnQgdG8gYXBwbHkgdGhlIGRpZmZlcmVudCBjb2xvciwgc2hhcGUsIGV0YywgZm9yICphbGwqIHBvaW50cywgeW91IGNhbiBkbyBpdCBieSBjaGFuZ2luZyB0aGUgcGFyYW1ldGVyIGluIFxgZ2VvbV9wb2ludCgpJy4KCmBgYHtyfQpjcmltZXMlPiUKICBnZ3Bsb3QoYWVzKHg9dmlvbGVudF9jcmltZV9yYXRlLHk9cHJvcGVydHlfY3JpbWVfcmF0ZSkpK2dlb21fcG9pbnQoc2l6ZT01KQoKY3JpbWVzJT4lCiAgZ2dwbG90KGFlcyh4PXZpb2xlbnRfY3JpbWVfcmF0ZSx5PXByb3BlcnR5X2NyaW1lX3JhdGUpKStnZW9tX3BvaW50KHNpemU9NSwgYWxwaGE9MC4yKSAjYWxwaGEgZm9yIHRyYW5zcGFyZW5jeTogZm9yIGRlbnNlbHkgcG9wdWxhdGVkIGRhdGEgcG9pbnRzCgpjcmltZXMlPiUKICBnZ3Bsb3QoYWVzKHg9dmlvbGVudF9jcmltZV9yYXRlLHk9cHJvcGVydHlfY3JpbWVfcmF0ZSkpK2dlb21fcG9pbnQoY29sPSJibHVlIikKCmNyaW1lcyU+JQogIGdncGxvdChhZXMoeD12aW9sZW50X2NyaW1lX3JhdGUseT1wcm9wZXJ0eV9jcmltZV9yYXRlKSkrZ2VvbV9wb2ludChzaGFwZT00KQoKY3JpbWVzJT4lCiAgZ2dwbG90KGFlcyh4PXZpb2xlbnRfY3JpbWVfcmF0ZSx5PXByb3BlcnR5X2NyaW1lX3JhdGUpKStnZW9tX3BvaW50KGNvbD0yLHNoYXBlPTIsc2l6ZSA9MykKCmNyaW1lcyU+JQogIGdncGxvdChhZXMoeD12aW9sZW50X2NyaW1lX3JhdGUseT1wcm9wZXJ0eV9jcmltZV9yYXRlKSkrCiAgZ2VvbV9wb2ludChjb2w9IiM4NjIyOUEiLHNoYXBlPTIsc2l6ZSA9MykrCiAgbGFicyh0aXRsZT0iVmlvbGVudCB2cy4gUHJvcGVydHkgQ3JpbWUgUmF0ZSIsIHg9IlZpb2xlbnQgQ3JpbWUgUmF0ZSIsIHk9IlByb3BlcnR5IENyaW1lIFJhdGUiKQoKYGBgCgojIyBEaWZmZXJlbnQgY29sb3JzLCBzaXplcywgZXRjLiBieSBncm91cHMKCklmIHlvdSB3YW50IHRvIHVzZSBkaWZmZXJlbnQgY29sb3JzIGJ5IGRpZmZlcmVudCBncm91cHMsIHlvdSBjYW4gZG8gaXQgZWFzaWx5IGJ5IHNldHRpbmcgaXQgaW4gYGFlcygpYCEgWW91IGNhbiBjaGFuZ2UgdGhlIGFlc3RoZXRpY3MgdG8gZGVsaXZlciBtb3JlIGluZm9ybWF0aW9uIG9uIGEgY2hhcnQuCgpgYGB7cn0KY3JpbWVzJT4lCiAgZ2dwbG90KGFlcyh4PXZpb2xlbnRfY3JpbWVfcmF0ZSx5PXByb3BlcnR5X2NyaW1lX3JhdGUsIHNpemU9b2ZmaWNlcl9hc3NhdWx0X3JhdGUpKStnZW9tX3BvaW50KCkKCmNyaW1lcyU+JQogIGdncGxvdChhZXMoeD12aW9sZW50X2NyaW1lX3JhdGUseT1wcm9wZXJ0eV9jcmltZV9yYXRlLCBjb2w9cmVnaW9uKSkrZ2VvbV9wb2ludCgpCmBgYAoKWW91IGNhbiBkbyBpdCBpbiBjb21iaW5hdGlvbiEKCmBgYHtyfQpjcmltZXMlPiUKICBnZ3Bsb3QoYWVzKHg9dmlvbGVudF9jcmltZV9yYXRlLHk9cHJvcGVydHlfY3JpbWVfcmF0ZSxzaXplPW9mZmljZXJfYXNzYXVsdF9yYXRlLGNvbD1yZWdpb24pKSsKICBnZW9tX3BvaW50KHNoYXBlPTEpCmBgYAoKTm90ZSB0aGF0IE9mZmljZXIgQXNzYXVsdCBSYXRlIGlzIHRoZSBudW1iZXIgb2YgcG9saWNlIG9mZmljZXJzIGtpbGxlZCBvciBhc3NhdWx0ZWQgaW4gdGhlIGxpbmUgb2YgZHV0eS4gVGhpcyBidWJibGUgY2hhcnQgbm93IHNob3dzIHRoYXQgcG9saWNlIG9mZmljZXJzIGFyZSBpbiBtb3JlIGRhbmdlciAoYXMgc2hvd24gaW4gYmlnZ2VyIGNpcmNsZXMpIGluIGNpdGllcyB3aXRoIGhpZ2hlciBjcmltZSByYXRlcy4KCiMjIEZhY2V0CgpZb3UgY2FuIGFsc28gZWFzaWx5IGNyZWF0ZSBzZXBhcmF0ZSBjaGFydHMgYnkgc3ViZ3JvdXBzIChpLmUuIHJlZ2lvbnMgaW4gdGhpcyBjYXNlKSB1c2luZyBgZmFjZXRfd3JhcCgpYCwgd2hpY2ggY3JlYXRlcyBjaGFydHMsIHdoaWNoIHNoYXJlIHRoZSBzYW1lIGF4ZXMsIGFuZCBkaXNwbGF5cyB0aGVtIGluIGEgcGFuZWwuCgpgYGB7cn0KY3JpbWVzJT4lCiAgZ2dwbG90KGFlcyh5PXByb3BlcnR5X2NyaW1lX3JhdGUseD12aW9sZW50X2NyaW1lX3JhdGUsc2l6ZT1vZmZpY2VyX2Fzc2F1bHRfcmF0ZSxjb2xvdXI9cmVnaW9uKSkrCiAgZ2VvbV9wb2ludChzaGFwZT0xKSsKICBmYWNldF93cmFwKH5yZWdpb24pCmBgYAoKIyMgQWRkIGEgc3RhdGlzdGljcyBsYXllcgoKV2UgY2FuIGFsc28gYWRkIHNvbWUgc3RhdGlzdGljYWwgYW5hbHlzaXMgcmVzdWx0cyB0byB0aGUgY2hhcnRzLgoKTE9FU1MsIHdoaWNoIGlzIGEgZGVmYXVsdCBzbW9vdGhpbmcgbWV0aG9kIG9mIGBnZW9tX3Ntb290aCgpYCwgaXMgYSBub24tcGFyYW1ldHJpYyBmb3JtIG9mIHJlZ3Jlc3Npb24gdGhhdCB1c2VzIGEgd2VpZ2h0ZWQsIHNsaWRpbmctd2luZG93LCBhdmVyYWdlIHRvIGNhbGN1bGF0ZSBhIGxpbmUgb2YgYmVzdCBmaXQuCgpgYGB7cn0KY3JpbWVzJT4lCiAgZ2dwbG90KGFlcyh4PXZpb2xlbnRfY3JpbWVfcmF0ZSx5PXByb3BlcnR5X2NyaW1lX3JhdGUpKSsKICBnZW9tX3BvaW50KHNoYXBlPTEpKwogIGdlb21fc21vb3RoKG1ldGhvZD1sb2VzcykKYGBgCgpBIGxpbmVhciByZWdyZXNzaW9uIG1vZGVsIGNhbiBiZSBhZGRlZCBpbnRvIGEgc2NhdHRlciBwbG90IGJ5IGFkZGluZyBzcGVjaWZ5aW5nIHRoZSBzbW9vdGhpbmcgbWV0aG9kIGFzICJsbSIuCgpgYGB7cn0KY3JpbWVzJT4lCiAgZ2dwbG90KGFlcyh4PXZpb2xlbnRfY3JpbWVfcmF0ZSx5PXByb3BlcnR5X2NyaW1lX3JhdGUpKSsKICBnZW9tX3BvaW50KHNoYXBlPTEpKwogIGdlb21fc21vb3RoKG1ldGhvZD1sbSkKYGBgCgpVc2luZyBgZmFjZXRfd3JhcCgpYCwgeW91IGNhbiBjb21wYXJlIHRoZSB0cmVuZCBieSBkaWZmZXJlbnQgcmVnaW9ucyBpbiB0aGUgVW5pdGVkIFN0YXRlcy5gZnVsbHJhbmdlPVRSVUVgIGV4dGVuZHMgdGhlIHNwYW4gb2YgdGhlIGxpbmVhciBtb2RlbCB0byB0aGUgZnVsbCByYW5nZS4KCmBgYHtyfQpjcmltZXMlPiUKICBnZ3Bsb3QoYWVzKHg9dmlvbGVudF9jcmltZV9yYXRlLHk9cHJvcGVydHlfY3JpbWVfcmF0ZSwgY29sPXJlZ2lvbikpKwogIGdlb21fcG9pbnQoc2hhcGU9MSkrCiAgZ2VvbV9zbW9vdGgobWV0aG9kPWxtLGZ1bGxyYW5nZT1UUlVFKSsKICBmYWNldF93cmFwKH5yZWdpb24pCmBgYAoKIyBCYXIgY2hhcnRzCgpBIGJhciBjaGFydCBpcyBhIHNpbXBsZSB3YXkgdG8gZGVwaWN0IHRoZSBmcmVxdWVuY2llcyBvZiB0aGUgdmFsdWVzIG9mIGEgKmNhdGVnb3JpY2FsKiBhdHRyaWJ1dGUuCgpIb3cgbWFueSBjaXRpZXMgYXJlIGNvbnRhaW5lZCBpbiB0aGlzIGRhdGFzZXQgYnkgcmVnaW9uPyBJbiBmYWN0LCB0aGUgZGF0YXNldCBpcyBhIHBhbmVsIGRhdGFzZXQgKGkuZS4gcmVwZWF0ZWQgb2JzZXJ2YXRpb25zIG92ZXIgdGltZSBmb3IgdGhlIHNhbWUgZW50aXRpZXMpIGF0IGEgY2l0eS15ZWFyIGxldmVsLCB3aGVyZSBlYWNoIGNpdHkgYXBwZWFycyBvbmNlIHBlciB5ZWFyLiBTbywgd2UgY2FuIGNvdW50IHRoZSBudW1iZXIgb2YgY2l0aWVzLCBpZiB3ZSBzZXQgYHllYXJgIHRvIGEgc3BlY2lmaWMgeWVhciAoZS5nLiBgeWVhcj0yMDAwYCksIGFuZCBjb3VudCB0aGUgbnVtYmVyIG9mIG9ic2VydmF0aW9ucy4KCkxldCdzIGZpbHRlciBkYXRhIHdpdGggYHllYXI9PTIwMDBgIGFuZCB0aGVuIGNhbGwgYGdncGxvdCgpYCB3aXRoIGBnZW9tX2JhcigpYCB0byBjcmVhdGUgYSBiYXIgY2hhcnQuCgpgYGB7cn0KY3JpbWVzJT4lCiAgZmlsdGVyKHllYXI9PTIwMDApJT4lCiAgZ2dwbG90KGFlcyh4PXJlZ2lvbikpKwogIGdlb21fYmFyKCkKYGBgCgojIEhpc3RvZ3JhbQoKQSBoaXN0b2dyYW0gc2hvd3MgdGhlIGZyZXF1ZW5jeSBkaXN0cmlidXRpb24gZm9yIGEgbnVtZXJpY2FsIGF0dHJpYnV0ZS4KClRoZSByYW5nZSBvZiBhIG51bWVyaWNhbCBhdHRyaWJ1dGUgaXMgZGlzY3JldGl6ZWQgaW50byBhIGZpeGVkIG51bWJlciBvZiBpbnRlcnZhbHMgKOKAnGJpbnPigJ0pLCB1c3VhbGx5IG9mIGVxdWFsIGxlbmd0aC4gRm9yIGVhY2ggaW50ZXJ2YWwsIHRoZSAoYWJzb2x1dGUpIGZyZXF1ZW5jeSBvZiB2YWx1ZXMgZmFsbGluZyBpbnRvIGVhY2ggaW50ZXJ2YWwgaXMgaW5kaWNhdGVkIGJ5IHRoZSBoZWlnaHQgb2YgYSBiYXIuCgpMZXQncyBleGFtaW5lIHRoZSBkaXN0cmlidXRpb24gb2YgdGhlIHByb3BlcnR5IGNyaW1lIHJhdGUuCgpgYGB7cn0KY3JpbWVzJT4lCiAgZ2dwbG90KGFlcyh4PXByb3BlcnR5X2NyaW1lX3JhdGUpKSsKICBnZW9tX2hpc3RvZ3JhbSgpCmBgYAoKIyMgQ2hhbmdlIGJpbiB3aWR0aCwgZmlsbCwgY29sb3IuLgoKVHJ5IGNoYW5naW5nIHRoZSB2YWx1ZSBvZiBgYmlud2lkdGhgLiBZb3Ugd2lsbCBzZWUgdGhlIHNoYXBlIG9mIHRoZSBoaXN0b2dyYW0gY2hhbmdlcy4gQWxzbywgYXMgd2UgZGlkIHdpdGggYSBzY2F0dGVycGxvdCwgeW91IGNhbiBjaGFuZ2UgdGhlIGNvbG9yIG9mIHRoZSBoaXN0b2dyYW0uCgpgYGB7cn0KY3JpbWVzJT4lCiAgZ2dwbG90KGFlcyh4PXByb3BlcnR5X2NyaW1lX3JhdGUpKSsKICBnZW9tX2hpc3RvZ3JhbShiaW53aWR0aD0xMDAwLCBjb2w9ImJsYWNrIixmaWxsPSJyZWQiKQpgYGAKCiMjIE92ZXJsYXBwaW5nIGhpc3RvZ3JhbXMKCldlIGNhbiBlYXNpbHkgY3JlYXRlIGhpc3RvZ3JhbXMgZm9yIGRpZmZlcmVudCByZWdpb25zIHVzaW5nIGBmYWNldF93cmFwKClgLgoKYGBge3J9CmNyaW1lcyU+JQogIGdncGxvdChhZXMoeD1wcm9wZXJ0eV9jcmltZV9yYXRlLCBmaWxsPXJlZ2lvbikpKwogIGdlb21faGlzdG9ncmFtKGJpbndpZHRoPTEwMCkrCiAgZmFjZXRfd3JhcCh+cmVnaW9uKQpgYGAKCkJ1dCB5b3UgY2FuIGFsc28gZGlzcGxheSB0aGVzZSBoaXN0b2dyYW1zIGluIG9uZSBjaGFydCB3aXRoIHZhcmlvdXMgb3B0aW9ucy4KCmBgYHtyfQpjcmltZXMlPiUKICBnZ3Bsb3QoYWVzKHg9cHJvcGVydHlfY3JpbWVfcmF0ZSxmaWxsPXJlZ2lvbikpKwogIGdlb21faGlzdG9ncmFtKGJpbndpZHRoPTEwMCkKCmNyaW1lcyU+JQogIGdncGxvdChhZXMoeD1wcm9wZXJ0eV9jcmltZV9yYXRlLGZpbGw9cmVnaW9uKSkrCiAgZ2VvbV9oaXN0b2dyYW0oYmlud2lkdGg9MTAwLGFscGhhPTAuMywgcG9zaXRpb249ImlkZW50aXR5IikKCmNyaW1lcyU+JQogIGdncGxvdChhZXMoeD1wcm9wZXJ0eV9jcmltZV9yYXRlLGZpbGw9cmVnaW9uKSkrCiAgZ2VvbV9oaXN0b2dyYW0oYmlud2lkdGg9MTAwLHBvc2l0aW9uPSJzdGFjayIpCgpjcmltZXMlPiUKICBnZ3Bsb3QoYWVzKHg9cHJvcGVydHlfY3JpbWVfcmF0ZSxmaWxsPXJlZ2lvbikpKwogIGdlb21faGlzdG9ncmFtKGJpbndpZHRoPTEwMDAscG9zaXRpb249ImRvZGdlIikKYGBgCgpJbnN0ZWFkIG9mIGEgaGlzdG9ncmFtLCB5b3UgY2FuIGNyZWF0ZSBhIGRlbnNpdHkgZnVuY3Rpb24gaW4gYSBzaW1pbGFyIG1hbm5lci4KCmBgYHtyfQpjcmltZXMlPiUKICBnZ3Bsb3QoYWVzKHg9cHJvcGVydHlfY3JpbWVfcmF0ZSwgZmlsbD1yZWdpb24pKSsKICBnZW9tX2RlbnNpdHkoYWxwaGE9MC41KQpgYGAKCiMgQm94IHBsb3QKCkEgYm94cGxvdCBpcyBhIHZlcnkgY29tcGFjdCB3YXkgdG8gdmlzdWFsaXplIGFuZCBzdW1tYXJpemUgdGhlIGtleSBzdGF0aXN0aWNzIG9mIGEgbnVtZXJpYyBhdHRyaWJ1dGUuCgpMZXQncyBleGFtaW5lIHRoZSBkaXN0cmlidXRpb24gb2YgdGhlIHByb3BlcnR5IGNyaW1lIHJhdGUgKHdoaWNoIHdpbGwgYmUgZGlzcGxheWVkIGluIHktYXhpcykgYnkgY2l0aWVzICh3aGljaCB3aWxsIGJlIHgtYXhpcykuIEJlY2F1c2Ugd2UgaGF2ZSB0b28gbWFueSBjaXRpZXMgaW4gb3VyIGRhdGFzZXRzLCBsZXQncyBmb2N1cyBvbiB0aGUgY2l0aWVzIGluIEZsb3JpZGEuCgpgYGB7cn0KY3JpbWVzJT4lCiAgZmlsdGVyKHN0YXRlPT0iRkwiKSU+JQogIGdncGxvdChhZXMoeD1jaXR5LHk9cHJvcGVydHlfY3JpbWVfcmF0ZSxmaWxsPWNpdHkpKSsKICBnZW9tX2JveHBsb3QoKQpgYGAKClRoZSB1cHBlciB3aGlza2VyIGV4dGVuZHMgZnJvbSB0aGUgaGluZ2UgdG8gdGhlIGxhcmdlc3QgdmFsdWUgbm8gZnVydGhlciB0aGFuIDEuNSBcKiBJUVIgZnJvbSB0aGUgaGluZ2UgKHdoZXJlIElRUiBpcyB0aGUgaW50ZXItcXVhcnRpbGUgcmFuZ2UsIG9yIGRpc3RhbmNlIGJldHdlZW4gdGhlIGZpcnN0IGFuZCB0aGlyZCBxdWFydGlsZXMpLiBUaGUgbG93ZXIgd2hpc2tlciBleHRlbmRzIGZyb20gdGhlIGhpbmdlIHRvIHRoZSBzbWFsbGVzdCB2YWx1ZSBhdCBtb3N0IDEuNSBcKiBJUVIgb2YgdGhlIGhpbmdlLiBEYXRhIGJleW9uZCB0aGUgZW5kIG9mIHRoZSB3aGlza2VycyBhcmUgY2FsbGVkICJvdXRseWluZyIgcG9pbnRzIGFuZCBhcmUgcGxvdHRlZCBpbmRpdmlkdWFsbHkuCgojIFRpbWUgU2VyaWVzIHdpdGggTGluZSBHcmFwaAoKTGV0J3MgZXhhbWluZSB0aGUgdHJlbmQgb2YgdGhlIHZpb2xlbnQgY3JpbWUgcmF0ZSBvZiB0aGUgY2l0aWVzIGluIE5ldyBZb3JrIHN0YXRlLiBMZXQncyBmaXJzdCBleGFtaW5lIHRoZSBkYXRhLgoKYGBge3J9CmNyaW1lcyU+JQogIGZpbHRlcihzdGF0ZT09Ik5ZIiklPiUKICBkaXN0aW5jdChjaXR5KQoKY3JpbWVzJT4lCiAgZmlsdGVyKHN0YXRlPT0iTlkiKQpgYGAKCkZvciBsaW5lIGdyYXBocywgdGhlIGRhdGEgcG9pbnRzIG11c3QgYmUgZ3JvdXBlZCBzbyB0aGF0IGl0IGtub3dzIHdoaWNoIHBvaW50cyB0byBjb25uZWN0LiBJZiB5b3Ugd2FudCB0byBjb25uZWN0IGFsbCBwb2ludHMsIHNldCBgZ3JvdXA9MWAuIEJlY2F1c2Ugd2Ugd2FudCB0byBjb25uZWN0IHRoZSBwb2ludHMgYnkgY2l0aWVzLCB3ZSB3aWxsIHNldCBgZ3JvdXA9Y2l0eWAuCgpgYGB7cn0KY3JpbWVzJT4lCiAgZmlsdGVyKHN0YXRlPT0iTlkiKSU+JQogICBnZ3Bsb3QoYWVzKHg9eWVhcix5PXZpb2xlbnRfY3JpbWVfcmF0ZSxncm91cD1jaXR5KSkrZ2VvbV9saW5lKCkKYGBgCgpCdXQgd2UgbG9zdCB0aGUgaW5mb3JtYXRpb24gYWJvdXQgd2hpY2ggbGluZSBpcyBmb3Igd2hpY2ggY2l0eS4gTGV0J3MgdXNlIGRpZmZlcmVudCB0eXBlcyBvciBjb2xvcnMgb2YgbGluZXMsIHNvIHRoYXQgd2UgY2FuIGRpc3Rpbmd1aXNoIHRoZW0uCgpgYGB7cn0KY3JpbWVzJT4lCiAgZmlsdGVyKHN0YXRlPT0iTlkiKSU+JQogICBnZ3Bsb3QoYWVzKHg9eWVhcix5PXZpb2xlbnRfY3JpbWVfcmF0ZSwgZ3JvdXA9Y2l0eSxjb2w9Y2l0eSkpK2dlb21fbGluZSgpCgpjcmltZXMlPiUKICBmaWx0ZXIoc3RhdGU9PSJOWSIpJT4lCiAgIGdncGxvdChhZXMoeD15ZWFyLHk9dmlvbGVudF9jcmltZV9yYXRlLCBncm91cD1jaXR5LGxpbmV0eXBlPWNpdHkpKStnZW9tX2xpbmUoKQpgYGAKCiMgQXNzaWdubWVudCAyCgpCeSBtb2RpZnlpbmcgdGhlIGNvZGUgYmVsb3csIGNyZWF0ZSBib3ggcGxvdHMgdGhhdCBzaG93IHRoZSByYW5nZSBvZiB0aGUgdmlvbGVudCBjcmltZSByYXRlIGZvciBlYWNoIHN0YXRlIGluIHRoZSBTb3V0aCByZWdpb24sIHdoZXJlIGVhY2ggYm94IHJlcHJlc2VudHMgYSBzdGF0ZS4gRllJLCBzaXggc3RhdGVzIGFyZSBjYXRlZ29yaXplZCBhcyBTb3V0aCBpbiB0aGUgZGF0YXNldC4gQWZ0ZXIgY3JlYXRpbmcgdGhlIGNoYXJ0LCBhbnN3ZXIgdGhlIGZvbGxvd2luZyBxdWVzdGlvbnMuCgpgYGB7cn0KY3JpbWVzICU+JQogIGZpbHRlcihyZWdpb24gPT0gIlNvdXRoIikgJT4lCiAgZ2dwbG90KGFlcyh4ID0gc3RhdGUsIHkgPSB2aW9sZW50X2NyaW1lX3JhdGUsIGZpbGw9c3RhdGUpKSArCiAgZ2VvbV9ib3hwbG90KCkKYGBgCgpRMS4gV2hpY2ggc3RhdGUgaGFzIHRoZSBjaXR5IHRoYXQgaGFzIHRoZSBsb3dlc3QgdmlvbGVudCBjcmltZSByYXRlIGluIHRoZSBTb3V0aCByZWdpb24/CgpLWTogS2VudHVja3kKClEyLiBXaGljaCBzdGF0ZSBoYXMgdGhlIGhpZ2hlc3QgbWVkaWFuIHZhbHVlIG9mIHRoZSB2aW9sZW50IGNyaW1lIHJhdGU/CgpUZW5uZXNzZWUgKFROKQoKUTMuIEJ5IG1vZGlmeWluZyB0aGUgY29kZSBiZWxvdywgY3JlYXRlIHNjYXR0ZXJwbG90cyB0aGF0IHNob3cgdGhlIHJlbGF0aW9uc2hpcCBiZXR3ZWVuIHRoZSBvZmZpY2VyIGFzc2F1bHQgcmF0ZSAoeC1heGlzKSBhbmQgdGhlIG11cmRlciByYXRlICh5LWF4aXMpIGJ5IHRoZSBzdGF0ZXMgaW4gdGhlIE5vcnRoZWFzdCByZWdpb24uIEl0IHdpbGwgcHJvZHVjZSBmb3VyIHNjYXR0ZXIgcGxvdHMgd2l0aCByZWdyZXNzaW9uIGxpbmVzLCBvbmUgZm9yIGVhY2ggc3RhdGUuCgpXaGljaCBzdGF0ZSBzaG93cyB0aGUgc3Ryb25nZXN0ICpuZWdhdGl2ZSogY29ycmVsYXRpb24gKGkuZS4gdGhlIHN0ZWVwZXIsIGRvd253YXJkIHNsb3BlIG9mIHJlZ3Jlc3Npb24gbGluZXMpPwoKTkogOiBOZXcgSmVyc2V5CgpgYGB7cn0KY3JpbWVzICU+JQogIGZpbHRlcihyZWdpb24gPT0gIk5vcnRoZWFzdCIpICU+JQogIGdncGxvdChhZXMoeCA9IG9mZmljZXJfYXNzYXVsdF9yYXRlLCB5ID0gbXVyZGVyX3JhdGUpKSArCiAgZ2VvbV9wb2ludChzaGFwZSA9IDEpICsKICBnZW9tX3Ntb290aChtZXRob2QgPSBsbSwgZnVsbHJhbmdlID0gVFJVRSkgKwogIGZhY2V0X3dyYXAofiBzdGF0ZSkKYGBgCgpRNC5CeSBtb2RpZnlpbmcgdGhlIGNvZGUgYmVsb3csIGNyZWF0ZSBhIGhpc3RvZ3JhbSB0aGF0IHNob3dzIHRoZSBkaXN0cmlidXRpb24gb2YgcHJvcGVydHkgY3JpbWUgcmF0ZSBpbiB5ZWFyIDIwMDIuIFNldCB0aGUgYmlud2lkdGg9MjAwMC4gV2hpY2ggb2YgdGhlIGJpbnMgY29udGFpbnMgdGhlIGxhcmdlc3QgbnVtYmVyIG9mIGNpdGllcz8KCmBgYHtyfQpjcmltZXMgJT4lCiAgZmlsdGVyKHllYXIgPT0gIjIwMDIiKSAlPiUKICBnZ3Bsb3QoYWVzKHggPSBwcm9wZXJ0eV9jcmltZV9yYXRlKSkgKwogIGdlb21faGlzdG9ncmFtKGJpbndpZHRoID0gMjAwMCwgY29sb3VyID0gImJsYWNrIiwgZmlsbCA9ICJ3aGl0ZSIpCmBgYAoKKDEpIFRoZSBiaW4gd2hvc2UgeC1heGlzIHZhbHVlcyBnbyBmcm9tIDAgdG8gMjUwMC4KKDIpIFRoZSBiaW4gd2hvc2UgeC1heGlzIHZhbHVlcyBnbyBmcm9tIDI1MDAgdG8gNTAwMC4KKDMpIFRoZSBiaW4gd2hvc2UgeC1heGlzIHZhbHVlcyBnbyBmcm9tIDUwMDAgdG8gNzUwMC4KKDQpIFRoZSBiaW4gd2hvc2UgeC1heGlzIHZhbHVlcyBnbyBmcm9tIDc1MDAgdG8gMTAwMDAuCig1KSBUaGUgYmluIHdob3NlIHgtYXhpcyB2YWx1ZXMgZ28gZnJvbSAxMDAwMC4gdG8gMTI1MDAKCkFuc3dlcjogVGhlIGJpbiB3aG9zZSB4LWF4aXMgdmFsdWVzIGdvIGZyb20gNTAwMCB0byA3NTAwLiBUaGlzIGJpbiBjb250YWlucyBtb3JlIHRoYW4gNDAgY2l0aWVzLCBtYWtpbmcgaXQgdGhlIG9uZSB3aXRoIHRoZSBsYXJnZXN0IG51bWJlciBvZiBjaXRpZXMgaW4gMjAwMi4KClE1LiBTaW1pbGFyIHRvIEFzc2lnbm1lbnQgMSwgZ2VuZXJhdGUgYSByZXBvcnQgZnJvbSAiQ3JlYXRpbmctQ2hhcnRzLVN0dWRlbnQuUm1kIi4gVGhpcyB0aW1lLCBwbGVhc2Uga25pdCBpdCBpbiBhIFdvcmQgZG9jdW1lbnQuIENoYW5nZSB0aGUgYXV0aG9yIG5hbWUgb24gdGhlIHRvcCBvZiB0aGlzIFIgbWFya2Rvd24gZmlsZSB0byB5b3VyIG5hbWUuIENvbXBpbGUgdGhpcyBSIG1hcmtkb3duIGZpbGUgaW50byBhIFdvcmQgZG9jdW1lbnQgYW5kIHN1Ym1pdCBpdCB0aHJvdWdoIHRoZSBjb3Vyc2UgQ2FudmFzLiBZb3VyIHJlcG9ydCBzaG91bGQgY29udGFpbiBhbGwgdGhlIGNvZGVzIGFuZCB0aGUgcmVzdWx0cyBvZiBpbi1jbGFzcyBleGVyY2lzZXMgYXMgd2VsbCBhcyB0aGUgY29kZXMgZm9yIHRoZSBhc3NpZ25tZW50IHF1ZXN0aW9ucy4KClE2LiBDcmVhdGUgYSBkYXNoYm9hcmQgd2l0aCBUYWJsZWF1IGJ5IGZvbGxvd2luZyB0aGUgaW5zdHJ1Y3Rpb24gaW4gIkNyZWF0aW5nLUNoYXJ0cy1UYWJsZWF1LmRvYyIuIEFmdGVyIGNyZWF0aW5nIGEgZGFzaGJvYXJkLCBleHBvcnQgeW91ciBUYWJsZWF1IGRhc2hib2FyZCB2aWV3IGFzIFBvd2VyUG9pbnQuIENsaWNrIOKAnEZpbGVcPkV4cG9ydCBBcyBQb3dlcnBvaW504oCdLCBhbmQgaW5jbHVkZSDigJxUaGlzIFZpZXfigJ0uIEl0IHdpbGwgY3JlYXRlIGEgUFBUIGZpbGUgdGhhdCBpbmNsdWRlcyBhIHNuYXBzaG90IG9mIHRoZSBkYXNoYm9hcmQuIFN1Ym1pdCB0aGlzIHBwdCBmaWxlIHRocm91Z2ggQ2FudmFzIGFzIHlvdXIgYW5zd2VyIGZvciBRdWVzdGlvbiA2Lgo=